//------------------------------------------------------------
//  Filename: fiber_pix_filter.v
//   
//  Author  : wlduan@gmail.com
//  Revise  : 2019-12-06 22:20
//  Description: 
//   
//  Copyright (C) 2014, YRBD, Inc. 					      
//  All Rights Reserved.                                       
//-------------------------------------------------------------
//
`timescale 1ns/1ps
 
module FIBER_PIX_FILTER ( 
    input  wire        clk_100mhz,
    input  wire        resetn    ,
    //camera input
    input  wire        filter_en,  
    input  wire [7:0]  pix_black,
    input  wire [15:0] x_org_cnt,
    input  wire [15:0] y_org_cnt,

    input  wire [8:0]  coproc_din,
    input  wire        coproc_v,

    output reg  [8:0]  filter_dout,
    output reg         filter_v
);      
//--------------------------------------------------------
// 1 2 1
// 2 4 2   weight_sets;
// 1 2 1   
//--------------------------------------------------------
reg[7:0]    frm_data       ;
reg         frm_last       ;
reg         frm_data_v     ;
reg[1:0]    linex_sel      ;
reg[10:0]   line_mem_addr  ;
//-----------------------------------------------------------
reg         lineA_mem_ena;
reg         lineA_mem_wea;
reg[7:0]    lineA_mem_dina;
reg         lineA_mem_enb;
reg[10:0]   lineA_mem_addrb;
wire[7:0]   lineA_mem_doutb;

reg         lineB_mem_ena;
reg         lineB_mem_wea;
reg[7:0]    lineB_mem_dina;
reg         lineB_mem_enb;
reg[10:0]   lineB_mem_addrb;
wire[7:0]   lineB_mem_doutb;

reg         lineC_mem_ena;
reg         lineC_mem_wea;
reg[7:0]    lineC_mem_dina;
reg         lineC_mem_enb;
reg[10:0]   lineC_mem_addrb;
wire[7:0]   lineC_mem_doutb;

reg[10:0]   lineA_mem_addra;
reg[10:0]   lineB_mem_addra; 
reg[10:0]   lineC_mem_addra; 
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        frm_data   <= 8'b0;  
        frm_last   <= 1'b0;  
        frm_data_v <= 1'b0; 
    end 
    else if(filter_en)begin 
        frm_data   <= (rgb_raw_data < pix_black)?{1'b0,rgb_raw_data[7:1]}:rgb_raw_data;  
        frm_last   <= rgb_raw_last;  
        frm_data_v <= rgb_raw_v;             
    end 
    else begin
        frm_data   <= 8'b0;  
        frm_last   <= 1'b0;  
        frm_data_v <= 1'b0;         
    end
end 
//--------------------------------------------------------
wire[15:0] sync_x_cnt = x_org_cnt - 1;
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        linex_sel <= 2'd0;
    end 
    else if(frm_data_v&frm_last)begin 
        linex_sel <= 2'd0;
    end
    else if(frm_data_v&&(line_mem_addr == sync_x_cnt))begin 
        linex_sel <= (linex_sel < 2'd2)?(linex_sel+1):2'd0; 
    end 
end  
//--------------------------------------------------------
always @(posedge clk) begin
    if(rst)begin 
        line_mem_addr   <= 11'b0;    
    end 
    else if(frm_data_v&frm_last)begin 
        line_mem_addr   <= 11'b0;    
    end 
    else if(frm_data_v)begin 
        line_mem_addr   <= (line_mem_addr < sync_x_cnt)? (line_mem_addr + 11'b1):'b0;   
    end
end 
//--------------------------------------------------------
always @(posedge clk) lineA_mem_addra <= line_mem_addr;
always @(posedge clk) lineB_mem_addra <= line_mem_addr;
always @(posedge clk) lineC_mem_addra <= line_mem_addr;
//--------------------------------------------------------
always @(posedge clk) begin
    if(rst)begin 
        lineA_mem_dina  <= 8'b0;
        lineA_mem_wea   <= 1'b0;
        lineA_mem_ena   <= 1'b0;
        lineB_mem_dina  <= 8'h0;
        lineB_mem_wea   <= 1'b0;
        lineB_mem_ena   <= 1'b0;
        lineC_mem_dina  <= 8'h0;
        lineC_mem_wea   <= 1'b0;
        lineC_mem_ena   <= 1'b0;
    end 
    else if(frm_data_v&frm_last)begin 
        lineA_mem_dina  <= 8'h0;
        lineA_mem_wea   <= 1'b0;
        lineA_mem_ena   <= 1'b0;
        lineB_mem_dina  <= 8'b0;
        lineB_mem_wea   <= 1'b0;
        lineB_mem_ena   <= 1'b0;
        lineC_mem_dina  <= 8'h0;
        lineC_mem_wea   <= 1'b0;
        lineC_mem_ena   <= 1'b0;
    end 
    else if(frm_data_v)begin 
        lineA_mem_dina  <= (linex_sel == 2'd0)?frm_data[7:0]:8'b0;
        lineA_mem_wea   <= (linex_sel == 2'd0)?1'b1:1'b0;
        lineA_mem_ena   <= (linex_sel == 2'd0)?1'b1:1'b0;
        lineB_mem_dina  <= (linex_sel == 2'd1)?frm_data[7:0]:8'b0;
        lineB_mem_wea   <= (linex_sel == 2'd1)?1'b1:1'b0;
        lineB_mem_ena   <= (linex_sel == 2'd1)?1'b1:1'b0;
        lineC_mem_dina  <= (linex_sel == 2'd2)?frm_data[7:0]:8'b0;
        lineC_mem_wea   <= (linex_sel == 2'd2)?1'b1:1'b0;
        lineC_mem_ena   <= (linex_sel == 2'd2)?1'b1:1'b0;
    end
    else begin
        lineA_mem_wea   <= 1'b0;
        lineA_mem_ena   <= 1'b0;
        lineB_mem_wea   <= 1'b0;
        lineB_mem_ena   <= 1'b0;
        lineC_mem_wea   <= 1'b0;
        lineC_mem_ena   <= 1'b0;
    end     
end  
//--------------------------------------------------------
reg         frm_data_v_ff1;
reg         frm_last_ff1;
reg[21:0]   linex_sel_ffx;
reg[10:0]   frm_data_v_ffx;
reg[10:0]   frm_last_ffx;
reg[54:0]   line_mem_addr_ffx;
//--------------------------------------------------------
always @(posedge clk) frm_data_v_ff1    <= frm_data_v;
always @(posedge clk) frm_last_ff1      <= frm_last;
//--------------------------------------------------------
always @(posedge clk) frm_data_v_ffx    <= {frm_data_v_ffx[9:0],frm_data_v_ff1};
always @(posedge clk) frm_last_ffx      <= {frm_last_ffx[9:0],frm_last_ff1};
always @(posedge clk) line_mem_addr_ffx <= {line_mem_addr_ffx[43:0],line_mem_addr};
always @(posedge clk) linex_sel_ffx     <= {linex_sel_ffx[19:0],linex_sel};
//--------------------------------------------------------
always @(posedge clk) begin
    if(rst)begin 
        lineA_mem_addrb <= 11'b0;
        lineB_mem_addrb <= 11'b0;
        lineC_mem_addrb <= 11'b0;
        lineA_mem_enb   <= 1'b0;  
        lineB_mem_enb   <= 1'b0;              
        lineC_mem_enb   <= 1'b0;              
    end 
    else if(frm_data_v_ffx[4])begin 
        lineA_mem_addrb <= line_mem_addr_ffx[54:44];
        lineB_mem_addrb <= line_mem_addr_ffx[54:44];
        lineC_mem_addrb <= line_mem_addr_ffx[54:44];
        lineA_mem_enb   <= 1'b1;   
        lineB_mem_enb   <= 1'b1;           
        lineC_mem_enb   <= 1'b1;           
    end 
    else begin
        lineA_mem_enb   <= 1'b0;   
        lineB_mem_enb   <= 1'b0;   
        lineC_mem_enb   <= 1'b0;           
    end
end 
//--------------------------------------------------------
reg[7:0] lineA_dout;
reg[7:0] lineB_dout;
reg[7:0] lineC_dout;
//--------------------------------------------------------
always @(posedge clk) begin
    if(rst)begin 
        lineA_dout <= 0;
        lineB_dout <= 0;            
        lineC_dout <= 0;            
    end 
    else begin //lineA_dout sync with frm_data_v_ffx[7]
        lineA_dout <= lineA_mem_doutb;
        lineB_dout <= lineB_mem_doutb;  
        lineC_dout <= lineC_mem_doutb;  
    end 
end 
//--------------------------------------------------------
reg[7:0] p00,p01,p02;
reg[7:0] p10,p11,p12;
reg[7:0] p20,p21,p22;
//--------------------------------------------------------
always @(posedge clk) begin
    if(rst)begin 
        {p00,p01,p02} <= 24'b0;    
        {p10,p11,p12} <= 24'b0;    
        {p20,p21,p22} <= 24'b0;    
    end 
    else if(frm_data_v_ffx[8]) begin
        if (linex_sel_ffx[19:18] == 2'b0) begin 
            {p00,p01,p02} <= {p01,p02,lineB_dout};    
            {p10,p11,p12} <= {p11,p12,lineC_dout};    
            {p20,p21,p22} <= {p21,p22,lineA_dout}; 
        end
        else if(linex_sel_ffx[19:18] == 2'b1) begin 
            {p00,p01,p02} <= {p01,p02,lineC_dout};    
            {p10,p11,p12} <= {p11,p12,lineA_dout};    
            {p20,p21,p22} <= {p21,p22,lineB_dout};             
        end
        else begin
            {p00,p01,p02} <= {p01,p02,lineA_dout};    
            {p10,p11,p12} <= {p11,p12,lineB_dout};    
            {p20,p21,p22} <= {p21,p22,lineC_dout};             
        end         
    end 
    else if(frm_last_ffx[8]) begin 
        {p00,p01,p02} <= 24'b0;    
        {p10,p11,p12} <= 24'b0;    
        {p20,p21,p22} <= 24'b0;            
    end
end 
//--------------------------------------------------------
reg[11:0] line0_sum;
reg[11:0] line1_sum;
reg[11:0] line2_sum;
reg       line_sum_v;
reg       line_sum_last;
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        line_sum_v    <= 1'b0;    
        line_sum_last <= 1'b0;    
    end 
    else begin 
        line_sum_v    <= frm_data_v_ffx[9];
        line_sum_last <= frm_last_ffx[9];
    end 
end 
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
         line0_sum <= 12'h0;   
         line1_sum <= 12'h0;   
         line2_sum <= 12'h0;   
    end 
    else if(frm_data_v_ffx[9])begin 
         line0_sum <= p00 + p02 + {p01,1'b0};  
         line1_sum <= p10 + p12 + {p11,1'b0};  
         line2_sum <= p20 + p22 + {p21,1'b0};  
    end 
end 
//--------------------------------------------------------
reg[11:0] matrix_sum;
reg       matrix_sum_v;
reg       matrix_sum_last;
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        matrix_sum   <= 12'h0;    
        matrix_sum_v <= 1'b0;    
    end 
    else if(line_sum_v)begin 
        matrix_sum   <= line0_sum + line2_sum + {line1_sum,1'b0};    
        matrix_sum_v <= 1'b1;    
    end 
    else begin
        matrix_sum_v <= 1'b0;    
    end
end 
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        matrix_sum_last <= 1'b0;    
    end 
    else begin 
        matrix_sum_last <= line_sum_last;    
    end 
end  
//--------------------------------------------------------
always @(posedge clk,posedge rst) begin
    if(rst)begin 
        filter_dout <= 'b0;    
        filter_v    <= 1'b0;    
    end 
    else begin 
        filter_dout <= {matrix_sum_last,matrix_sum[11:4]};    
        filter_v    <= matrix_sum_v ;   
    end 
end  

//--------------------------------------------------------
dp_ram_bmem DP_RAM_inst0(
    .clka  ( clk             ) ,
    .clkb  ( clk             ) ,
    .ena   ( lineA_mem_ena   ) ,
    .wea   ( lineA_mem_wea   ) ,
    .addra ( lineA_mem_addra ) ,
    .dina  ( lineA_mem_dina  ) ,
    .enb   ( lineA_mem_enb   ) ,
    .addrb ( lineA_mem_addrb ) ,
    .doutb ( lineA_mem_doutb )
);
//--------------------------------------------------------
dp_ram_bmem DP_RAM_inst1(
    .clka  ( clk             ) ,
    .clkb  ( clk             ) ,
    .ena   ( lineB_mem_ena   ) ,
    .wea   ( lineB_mem_wea   ) ,
    .addra ( lineB_mem_addra ) ,
    .dina  ( lineB_mem_dina  ) ,
    .enb   ( lineB_mem_enb   ) ,
    .addrb ( lineB_mem_addrb ) ,
    .doutb ( lineB_mem_doutb )
);
//--------------------------------------------------------
dp_ram_bmem DP_RAM_inst2(
    .clka  ( clk             ) ,
    .clkb  ( clk             ) ,
    .ena   ( lineC_mem_ena   ) ,
    .wea   ( lineC_mem_wea   ) ,
    .addra ( lineC_mem_addra ) ,
    .dina  ( lineC_mem_dina  ) ,
    .enb   ( lineC_mem_enb   ) ,
    .addrb ( lineC_mem_addrb ) ,
    .doutb ( lineC_mem_doutb )
);



endmodule
